package com.developer.platform.domain.service.impl;

import static com.developer.platform.RedisConstant.AUTHORIZING_KEY;
import static com.developer.platform.RedisConstant.LOGIN_TOKEN_KEYS;

import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.developer.platform.domain.security.AuthenticationInfo;
import com.developer.platform.domain.security.UserDetails;
import com.developer.platform.domain.service.IAuthenticationSource;
import com.developer.platform.infrastructure.error.SecurityErrorType;
import com.veeker.core.exceptions.BusinessException;
import com.veeker.redis.utils.RedisUtil;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

/**
 * @author ：qiaoliang
 * @date ：2020-11-09
 */
@Service
public class AuthenticationSource implements IAuthenticationSource {

    @Override
    public AuthenticationInfo loadAuthentication(String token) {
        BusinessException.isNull(token, SecurityErrorType.NO_ACCESS_ERROR);
        UserDetails userDetails = null;
        try{
            userDetails = (UserDetails)RedisUtil.hashGet(LOGIN_TOKEN_KEYS , getSymmetricCrypto().decryptStr(token));
        }catch (Exception e){
            throw new BusinessException(SecurityErrorType.NO_ACCESS_ERROR);
        }
        BusinessException.isNull(userDetails, SecurityErrorType.NO_ACCESS_ERROR);
        return new AuthenticationInfo(userDetails);
    }

    @Override
    public String loadGenerateToken(Authentication authenticationInfo) {
        //  生成Token
        long expiresIn = 60 * 60 * 24 * 7L;
        UserDetails authUserDetails = (UserDetails)authenticationInfo.getPrincipal();
        // 设置用户为登录状态
        RedisUtil.hashsSet(LOGIN_TOKEN_KEYS, Long.toString(authUserDetails.getId()),authUserDetails,expiresIn);
        //  生成访问令牌
        return getSymmetricCrypto().encryptBase64(Long.toString(authUserDetails.getId()));
    }

    @Override
    public void removeToken(String token) {
        this.kickOut(Long.parseLong(getSymmetricCrypto().decryptStr(token)));
    }

    @Override
    public void kickOut(Long id) {
        RedisUtil.delectHash(LOGIN_TOKEN_KEYS, String.valueOf(id));
        this.removeResources(id);
    }

    @Override
    public void removeResources(Long id) {
        RedisUtil.delectHash(AUTHORIZING_KEY, String.valueOf(id));
    }

    private SymmetricCrypto getSymmetricCrypto(){
        return new SymmetricCrypto(SymmetricAlgorithm.AES, "QDAOVsEECSWXRoJz".getBytes());
    }

}
